/**
 Team: Dream-Lab
 Author: مۇختەرجان مەخمۇت (yeganaaa@163.com)
 Time: 2020/9/25 11:53 AM GMT+06:00
 **/

import { _decorator, Component, Node, systemEvent, SystemEvent, EventKeyboard, ButtonComponent, EventHandler, Event, SystemEventType, EventTouch, Vec2, CCBoolean} from 'cc';

const {ccclass, property} = _decorator;

@ccclass('ControlPad')
export class ControlPad extends Component {
    @property({type: CCBoolean})
    public useKeyboardArrowKeys: boolean = true
    @property([EventHandler])
    public onUp: EventHandler[] = []
    @property([EventHandler])
    public onDown: EventHandler[] = []
    @property([EventHandler])
    public onLeft: EventHandler[] = []
    @property([EventHandler])
    public onRight: EventHandler[] = []
    @property([EventHandler])
    public onTouchRelease: EventHandler[] = []
    @property({type: Node})
    public touchTargetNode: Node = null
    // @property({type: Node})
    // public nodeThatDetectTouchEnd: Node = null

    /**
     * arrowStates[0] is top
     * arrowStates[1] is right
     * arrowStates[2] is bottom
     * arrowStates[3] is left
     * @private
     */
    private arrowStates = [false, false, false, false]

    protected start() {
        this._registerEvents()
        // this._touchStartLocation = new Vec2(this.touchTargetNode.width / 2, this.touchTargetNode.height / 2)
    }

    public destroy() {
        this._unregisterEvents()
        super.destroy()
    }

    private _registerEvents() {
        this.touchTargetNode.on(Node.EventType.TOUCH_START, this._onTouchStart, this)
        this.touchTargetNode.on(Node.EventType.TOUCH_MOVE, this._onTouchMove, this)
        this.touchTargetNode.on(Node.EventType.TOUCH_END, this._onTouchEnd, this)
        this.touchTargetNode.on(Node.EventType.TOUCH_CANCEL, this._onTouchEnd, this)
        if (!this.useKeyboardArrowKeys) return
        systemEvent.on(SystemEvent.EventType.KEY_DOWN, this._onKeyDown, this)
        systemEvent.on(SystemEvent.EventType.KEY_UP, this._onKeyUp, this)
    }
    private _unregisterEvents() {
        this.touchTargetNode.off(Node.EventType.TOUCH_START, this._onTouchStart, this)
        this.touchTargetNode.off(Node.EventType.TOUCH_MOVE, this._onTouchMove, this)
        this.touchTargetNode.off(Node.EventType.TOUCH_END, this._onTouchEnd, this)
        this.touchTargetNode.off(Node.EventType.TOUCH_CANCEL, this._onTouchEnd, this)
        if (!this.useKeyboardArrowKeys) return
        systemEvent.off(SystemEvent.EventType.KEY_DOWN, this._onKeyUp, this)
        systemEvent.off(SystemEvent.EventType.KEY_UP, this._onKeyUp, this)
    }
    private _touchStartLocation: Vec2 = new Vec2(0, 0)
    private _onTouchStart(event: EventTouch) {
        this._touchStartLocation = event.getTouches()[0].getLocation()
        this._onTouchMove(event)
    }
    private _onTouchMove(event: EventTouch) {
        const location = event.getTouches()[0].getLocation()
        const distanceX = Math.abs(location.x - this._touchStartLocation.x)
        const distanceY = Math.abs(location.y - this._touchStartLocation.y)
        if (distanceX < 40 && distanceY < 40) return
        const radian = Math.atan2(location.y - this._touchStartLocation.y, location.x - this._touchStartLocation.x)
        const radianUnit = Math.PI / 4
        if (radian > radianUnit && radian < radianUnit * 3) this._onUp()
        if (radian < -radianUnit && radian > -(radianUnit * 3)) this._onDown()
        if (radian > -radianUnit && radian < radianUnit) this._onRight()
        if ((radian > radianUnit * 3 && radian < radianUnit * 4) || (radian < -(radianUnit * 3) && radian > -(radianUnit * 4))) this._onLeft()
    }
    private _onTouchEnd(event: EventTouch) {
        this._onKeyUp(null)
    }

    private _onKeyDown(event: EventKeyboard) {
        const isGo = event.keyCode == 87 || event.keyCode == 38
        const isBack = event.keyCode == 83 || event.keyCode == 40
        const isRight = event.keyCode == 68 || event.keyCode == 39
        const isLeft = event.keyCode == 65 || event.keyCode == 37
        isBack && this._onDown()
        isGo && this._onUp()
        isRight && this._onRight()
        isLeft && this._onLeft()
    }
    private _onKeyUp(event: EventKeyboard) {
        this._setArrowsStateToFalse()
        this.onTouchRelease && this.onTouchRelease.forEach(handler => handler.emit(null))
    }
    private _setArrowsStateToFalse() {
        for (let index = 0; index < this.arrowStates.length; index++) {
            this.arrowStates[index] = false
        }
    }
    private _onUp() {
        if (this.arrowStates[0]) return
        this._setArrowsStateToFalse()
        this.arrowStates[0] = true
        this.onUp.forEach(handler => handler.emit(null))
    }
    private _onDown() {
        if (this.arrowStates[2]) return
        this._setArrowsStateToFalse()
        this.arrowStates[2] = true
        this.onDown.forEach(hander => hander.emit(null))
    }
    private _onRight() {
        if (this.arrowStates[1]) return
        this._setArrowsStateToFalse()
        this.arrowStates[1] = true
        this.onRight.forEach(handler => handler.emit(null))
    }
    private _onLeft() {
        if (this.arrowStates[3]) return
        this._setArrowsStateToFalse()
        this.arrowStates[3] = true
        this.onLeft.forEach(handler => handler.emit(null))
    }
}
